package com.sunday.common.easy.excel.listener;

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.exception.ExcelDataConvertException;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.excel.util.ListUtils;
import com.sunday.common.core.enums.ErrorCodeEnum;
import com.sunday.common.core.exception.BusinessException;
import com.sunday.common.core.exception.CoreException;
import lombok.extern.slf4j.Slf4j;

import java.util.List;
import java.util.function.Consumer;

/**
 * 全量信息读取，超过最大数量报错
 * https://easyexcel.opensource.alibaba.com/docs/current/quickstart/read
 *
 * @author zsy
 * @since 2022/12/2
 */
@Slf4j
public class EasyExcelAllReadListener<T> implements ReadListener<T> {

    private static final long DEFAULT_READ_MAX_COUNT = 10000;
    /**
     * 当前指针
     */
    private long currPointer = 0;
    /**
     * 最大读取条数
     */
    private long readMaxCount;
    /**
     * 进行方法实现
     */
    private Consumer<List<T>> dataProcessor;
    /**
     * 解析异常是否阻断, 内部业务异常必须阻断
     */
    private boolean ignoreError;
    /**
     * 临时存储
     */
    private List<T> cachedDataList = ListUtils.newArrayListWithExpectedSize((int) DEFAULT_READ_MAX_COUNT);

    public EasyExcelAllReadListener(Consumer<List<T>> dataProcessor) {
        this(DEFAULT_READ_MAX_COUNT, true, dataProcessor);
    }

    public EasyExcelAllReadListener(long readMaxCount, Consumer<List<T>> dataProcessor) {
        this(readMaxCount, true, dataProcessor);
    }

    public EasyExcelAllReadListener(boolean ignoreError, Consumer<List<T>> dataProcessor) {
        this(DEFAULT_READ_MAX_COUNT, ignoreError, dataProcessor);
    }

    public EasyExcelAllReadListener(long readMaxCount, boolean ignoreError, Consumer<List<T>> dataProcessor) {
        this.readMaxCount = readMaxCount;
        this.ignoreError = ignoreError;
        this.dataProcessor = dataProcessor;
    }

    @Override
    public void invoke(T data, AnalysisContext context) {
//        log.info("解析到一条数据:{}", data);
        cachedDataList.add(data);
        currPointer++;
        if (currPointer > readMaxCount) {
            throw new BusinessException(ErrorCodeEnum.A0_425);
        }
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        if (cachedDataList.size() > 0) {
            // 这里也要保存数据，确保最后遗留的数据也存储到数据库
            dataProcessor.accept(cachedDataList);
        }
        log.info("所有数据解析完成！");
    }

    /**
     * 所有的监听器接收这个方法时，任何一个监听器做一个错误报告。如果在此抛出异常，则整个读取将终止
     */
    @Override
    public void onException(Exception exception, AnalysisContext context) {
        // log.error("解析失败，但是继续解析下一行 : {}", exception.getMessage());
        log.error("Excel 解析失败 : {}", exception.getMessage());
        // 如果是某一个单元格的转换异常 能获取到具体行号
        // 如果要获取头的信息 配合invokeHeadMap使用
        if (exception instanceof ExcelDataConvertException excelDataConvertException) {
            log.error("第 {} 行，第 {} 列解析异常，数据为 : {}",
                    excelDataConvertException.getRowIndex(),
                    excelDataConvertException.getColumnIndex(),
                    excelDataConvertException.getCellData());
            StringBuffer sb = new StringBuffer();
            sb.append("[第 ").append(excelDataConvertException.getRowIndex())
                    .append(" 行，第 ").append(excelDataConvertException.getColumnIndex())
                    .append(" 列解析异常]");
            throw new BusinessException(ErrorCodeEnum.A0_700, sb.toString(), true);
        }
        if (exception instanceof CoreException coreException) {
            throw coreException;
        }
        if (ignoreError) {
            throw new BusinessException(ErrorCodeEnum.A0_700);
        }
    }

}
